package me.firstapp.service.shop.impl;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import me.firstapp.common.exception.ServiceException;
import me.firstapp.common.exception.StatusHouse;
import me.firstapp.common.utils.DateUtils;
import me.firstapp.common.utils.MD5Utils;
import me.firstapp.common.utils.Page;
import me.firstapp.common.utils.StrUtils;
import me.firstapp.module.bbs.Member;
import me.firstapp.module.bbs.MemberPointAccountTrace;
import me.firstapp.module.bbs.PointAccount;
import me.firstapp.module.bbs.ShopNotification;
import me.firstapp.module.shop.Address;
import me.firstapp.module.shop.DistributeCall;
import me.firstapp.module.shop.Order;
import me.firstapp.module.shop.OrderItem;
import me.firstapp.module.shop.Product;
import me.firstapp.module.shop.ProductSkuRelation;
import me.firstapp.module.shop.ShoppingCart;
import me.firstapp.module.shop.ShoppingCartItem;
import me.firstapp.module.system.CommonSequence;
import me.firstapp.repository.bbs.MemberPointAccountTraceRepository;
import me.firstapp.repository.bbs.MemberRepository;
import me.firstapp.repository.bbs.PointAccountRepository;
import me.firstapp.repository.bbs.ShopNotificationRepository;
import me.firstapp.repository.shop.AddressRepository;
import me.firstapp.repository.shop.DistributeCallRepository;
import me.firstapp.repository.shop.OrderItemRepository;
import me.firstapp.repository.shop.OrderRepository;
import me.firstapp.repository.shop.ProductRepository;
import me.firstapp.repository.shop.ProductSkuRelationRepository;
import me.firstapp.repository.shop.ShoppingCartItemRepository;
import me.firstapp.repository.shop.ShoppingCartRepository;
import me.firstapp.repository.system.CommonSequenceRepository;
import me.firstapp.service.shop.OrderService;

@Service
public class OrderServiceImpl implements OrderService {

	@Autowired
	private CommonSequenceRepository orderSequenceRepository;

	@Autowired
	private MemberRepository memberRepository;

	@Autowired
	private OrderRepository orderRepository;

	@Autowired
	private OrderItemRepository orderItemRepository;

	@Autowired
	private AddressRepository addressRepository;

	@Autowired
	private ShoppingCartRepository shoppingCartRepository;

	@Autowired
	private ShoppingCartItemRepository shoppingCartItemRepository;

	@Autowired
	private PointAccountRepository pointAccountRepository;

	@Autowired
	private MemberPointAccountTraceRepository memberPointAccountTraceRepository;

	@Autowired
	private ProductSkuRelationRepository productSkuRelationRepository;

	@Autowired
	private ShopNotificationRepository shopNotificationRepository;

	@Autowired
	private DistributeCallRepository distributeCallRepository;

	@Autowired
	private ProductRepository productRepository;

	@Override
	public Order addOrder(Long memberId, String remark, Long apiClientId) {
		if (memberId == null) {
			throw new ServiceException(StatusHouse.COMMON_STATUS_PARAM_REQUIRED_ERROR, "会员id");
		}
		Member member = (Member) memberRepository.findMemberById(memberId, apiClientId);
		if (member == null) {
			throw new ServiceException(StatusHouse.MEMBER_NOT_FOUND);
		}

		Address address = addressRepository.findAddressByMemberId(memberId, apiClientId);
		if (address == null) {
			throw new ServiceException(StatusHouse.ADDRESS_NOT_FOUND);
		}

		ShoppingCart shoppingCart = shoppingCartRepository.findMemberShoppingCart(memberId, apiClientId);
		if (shoppingCart == null) {
			throw new ServiceException(StatusHouse.SHOPPING_CART_NOT_EXIST);
		}

		List<ShoppingCartItem> shoppingCartItems = shoppingCartItemRepository
				.findShoppingCartItemList(shoppingCart.getId());
		if (shoppingCartItems == null || shoppingCartItems.isEmpty()) {
			throw new ServiceException(StatusHouse.CART_IS_EMPTY);
		}

		CommonSequence orderSequence = new CommonSequence();
		orderSequenceRepository.save(orderSequence);

		Order order = new Order();
		order.setOrderNo(createOrderNo(orderSequence.getId()));
		order.setMember(member);
		order.setStatus(0);
		order.setCounts(shoppingCart.getCounts());
		order.setValue(shoppingCart.getValue());
		order.setReceiveName(address.getName());
		order.setReceiveAddress(address.getProvince() + address.getCity() + address.getDistrict() + " "
				+ address.getDetail() + " " + address.getName() + " " + address.getMobile());
		order.setRemark(remark);
		order.setCreateTime(new Date());
		order.setApiClientId(apiClientId);
		orderRepository.save(order);

		List<OrderItem> orderItems = new ArrayList<OrderItem>();
		for (ShoppingCartItem shoppingCartItem : shoppingCartItems) {
			OrderItem orderItem = new OrderItem();
			orderItem.setOrderId(order.getId());
			orderItem.setProduct(shoppingCartItem.getProduct());
			orderItem.setCounts(shoppingCartItem.getCounts());
			orderItem.setValue(shoppingCartItem.getValue());
			orderItem.setProductSkuRelation(shoppingCartItem.getProductSkuRelation());
			orderItem.setCommentStatus(0);
			orderItems.add(orderItem);
			orderItemRepository.save(orderItem);
		}
		order.setItems(orderItems);

		// 减少库存
		for (OrderItem orderItem : orderItems) {
			ProductSkuRelation rel = orderItem.getProductSkuRelation();
			Integer newStock = rel.getStock() - orderItem.getCounts();
			rel.setStock(newStock);
			productSkuRelationRepository.update(rel);
			if (rel.getIsDefault() == 1) {
				Product product = orderItem.getProduct();
				if (product.getProductSkuRelationId().equals(rel.getId())) {
					product.setStock(rel.getStock());
					productRepository.update(product);
				}
			}
		}

		// 清空购物车
		Long[] ids = new Long[shoppingCartItems.size()];
		for (int i = 0; i < shoppingCartItems.size(); i++) {
			ids[i] = shoppingCartItems.get(i).getId();
		}
		shoppingCartItemRepository.delete(ids);
		shoppingCart.setCounts(0);
		shoppingCart.setValue(0d);
		shoppingCartRepository.update(shoppingCart);

		// 通知
		try {
			ShopNotification shopNotification = new ShopNotification();
			shopNotification.setContent("您的订单(订单号：" + order.getOrderNo() + ") 还未支付，提醒您尽快付款，未支付的订单将在两小时后系统自动取消。");
			shopNotification.setIsRead(0);
			shopNotification.setNotifyTime(new Date());
			shopNotification.setToMember(member);
			shopNotification.setAction(0);
			shopNotification.setOrder(order);
			shopNotification.setApiClientId(apiClientId);
			shopNotificationRepository.save(shopNotification);
		} catch (Exception e) {
			e.printStackTrace();
		}

		return order;
	}

	private String createOrderNo(Long sequenceNumber) {
		String prefix = DateUtils.getNowStr("yyyyMMdd");
		String suffix = String.format("%1$010d", sequenceNumber);
		String orderNo = prefix + suffix;
		return orderNo;
	}

	@Override
	public Order findOrderByOrderNo(String orderNo, boolean itemsFlag, Long apiClientId) {
		if (StrUtils.isNULL(orderNo)) {
			throw new ServiceException(StatusHouse.COMMON_STATUS_PARAM_REQUIRED_ERROR, "订单号");
		}
		Order order = orderRepository.findOrderByOrderNo(orderNo, apiClientId);
		if (itemsFlag == true) {
			List<OrderItem> items = orderItemRepository.findOrderItemsByOrderId(order.getId());
			order.setItems(items);
		}
		return order;
	}

	@Override
	public Order executePayOrder(Long memberId, String orderNo, String password, Long apiClientId) {
		if (memberId == null) {
			throw new ServiceException(StatusHouse.COMMON_STATUS_PARAM_REQUIRED_ERROR, "会员id");
		}
		if (StrUtils.isNULL(orderNo)) {
			throw new ServiceException(StatusHouse.COMMON_STATUS_PARAM_REQUIRED_ERROR, "订单号");
		}
		PointAccount pointAccount = pointAccountRepository.findByMemberId(memberId, apiClientId);
		if (pointAccount == null) {
			throw new ServiceException(StatusHouse.POINT_ACCOUNT_NOT_EXIST);
		}
		Order order = orderRepository.findOrderByMemberIdAndOrderNo(memberId, orderNo, apiClientId);
		if (order == null) {
			throw new ServiceException(StatusHouse.ORDER_NOT_EXIST);
		}
		if (order.getStatus() != 0) {
			throw new ServiceException(StatusHouse.ORDER_PAYED_OR_CANCLED);
		}
		if (!MD5Utils.verify(password, pointAccount.getPassword())) {
			throw new ServiceException(StatusHouse.PAY_PASSWORD_IS_WRONG);
		}
		Double currentValue = pointAccount.getCurrentValue();
		if (!MD5Utils.verify(currentValue.toString(), pointAccount.getSalt())) {
			throw new ServiceException(StatusHouse.POINT_ACCOUNT_NOT_NORMAL);
		}

		Double orderValue = order.getValue();
		BigDecimal bCurrentValue = new BigDecimal(currentValue);
		BigDecimal bOrderValue = new BigDecimal(orderValue);
		Double afterValue = bCurrentValue.subtract(bOrderValue).doubleValue();
		if (afterValue < 0) {
			throw new ServiceException(StatusHouse.CURRENT_VALUE_IS_NOT_ENOUGH);
		}
		MemberPointAccountTrace memberPointAccountTrace = new MemberPointAccountTrace();
		memberPointAccountTrace.setPointAccountId(pointAccount.getId());
		memberPointAccountTrace.setBeforeValue(pointAccount.getCurrentValue());
		memberPointAccountTrace.setChangeValue(-order.getValue());
		memberPointAccountTrace.setAfterValue(afterValue);
		// 更新积分账户
		pointAccount.setCurrentValue(afterValue);
		pointAccount.setSalt(MD5Utils.generate(afterValue.toString()));
		pointAccountRepository.update(pointAccount);
		// 更新积分变动记录
		memberPointAccountTrace.setRemark("订单支付");
		memberPointAccountTrace.setChangeTime(new Date());
		memberPointAccountTrace.setApiClientId(apiClientId);
		memberPointAccountTraceRepository.save(memberPointAccountTrace);
		// 更新订单状态
		order.setStatus(1);
		orderRepository.update(order);

		// 通知
		try {
			ShopNotification shopNotification = new ShopNotification();
			shopNotification.setContent("恭喜您，您的订单(订单号：" + order.getOrderNo() + ") 支付成功！");
			shopNotification.setIsRead(0);
			shopNotification.setNotifyTime(new Date());
			shopNotification.setToMember(order.getMember());
			shopNotification.setAction(1);
			shopNotification.setOrder(order);
			shopNotification.setApiClientId(apiClientId);
			shopNotificationRepository.save(shopNotification);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return order;
	}

	@Override
	public Page<Order> findOrderPage(Integer pageNo, Integer pageSize, Long memberId, Integer status,
			Long apiClientId) {
		Page<Order> orderPage = orderRepository.findOrderPage(pageNo, pageSize, memberId, status, apiClientId);
		Collection<Order> orders = orderPage.getEntities();
		List<Order> newOrderList = new ArrayList<>();
		List<Order> orderList = new ArrayList<>(orders);
		for (Order order : orderList) {
			List<OrderItem> items = orderItemRepository.findOrderItemsByOrderId(order.getId());
			order.setItems(items);
			newOrderList.add(order);
			items = null;
		}
		orderList = null;
		orderPage.setEntities(newOrderList);
		return orderPage;
	}

	@Override
	public Order executeCancelOrder(String orderNo, Long apiClientId) {
		if (StrUtils.isNULL(orderNo)) {
			throw new ServiceException(StatusHouse.COMMON_STATUS_PARAM_REQUIRED_ERROR, "订单号");
		}
		Order order = orderRepository.findOrderByOrderNo(orderNo, apiClientId);
		if (order == null) {
			throw new ServiceException(StatusHouse.ORDER_NOT_EXIST);
		}
		if (order.getStatus() != 0) {
			throw new ServiceException(StatusHouse.ORDER_CAN_NOT_SET_CANCEL);
		}
		order.setStatus(4);
		orderRepository.update(order);
		List<OrderItem> orderItems = orderItemRepository.findOrderItemsByOrderId(order.getId());
		for (OrderItem orderItem : orderItems) {
			ProductSkuRelation rel = orderItem.getProductSkuRelation();
			rel.setStock(rel.getStock() + orderItem.getCounts());
			productSkuRelationRepository.update(rel);
			if (rel.getIsDefault() == 1) {
				Product product = orderItem.getProduct();
				if (product.getProductSkuRelationId().equals(rel.getId())) {
					product.setStock(rel.getStock());
					productRepository.update(product);
				}
			}
		}
		// 通知
		try {
			ShopNotification shopNotification = new ShopNotification();
			shopNotification.setContent("您的订单(订单号：" + order.getOrderNo() + ") 已被取消该。");
			shopNotification.setIsRead(0);
			shopNotification.setNotifyTime(new Date());
			shopNotification.setToMember(order.getMember());
			shopNotification.setAction(2);
			shopNotification.setOrder(order);
			shopNotification.setApiClientId(apiClientId);
			shopNotificationRepository.save(shopNotification);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return order;
	}

	@Override
	public Page<Order> findOrderPage(Integer pageNo, Integer pageSize, Map<String, Object> searchParams,
			String sortParam, String sortType, Date startTime, Date endTime, Long apiClientId) {
		return orderRepository.findOrderPage(pageNo, pageSize, searchParams, sortParam, sortType, startTime, endTime,
				apiClientId);
	}

	@Override
	public Order executeDistributeOrder(String orderNo, String expressName, String expressNo, Long apiClientId) {
		if (StrUtils.isNULL(orderNo)) {
			throw new ServiceException(StatusHouse.COMMON_STATUS_PARAM_REQUIRED_ERROR, "订单号");
		}
		Order order = orderRepository.findOrderByOrderNo(orderNo, apiClientId);
		if (order == null) {
			throw new ServiceException(StatusHouse.ORDER_NOT_EXIST);
		}
		if (order.getStatus() != 1) {
			throw new ServiceException(StatusHouse.ORDER_CAN_NOT_SET_DISTRIBUTE);
		}
		order.setStatus(2);
		order.setExpressName(expressName);
		order.setExpressNo(expressNo);
		orderRepository.update(order);

		try {
			// 通知
			ShopNotification shopNotification = new ShopNotification();
			shopNotification.setContent("您的订单(订单号：" + order.getOrderNo() + ") 已发货，可在'我的订单'里查看具体信息。");
			shopNotification.setIsRead(0);
			shopNotification.setNotifyTime(new Date());
			shopNotification.setToMember(order.getMember());
			shopNotification.setAction(3);
			shopNotification.setOrder(order);
			shopNotification.setApiClientId(apiClientId);
			shopNotificationRepository.save(shopNotification);

			// 处理订单发货提醒状态
			DistributeCall distributeCall = distributeCallRepository.findByOrderNo(orderNo, apiClientId);
			if (distributeCall != null) {
				if (distributeCall.getStatus() == 0) {
					distributeCall.setStatus(1);
					distributeCallRepository.update(distributeCall);
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return order;
	}

	@Override
	public Order executeCompleteOrder(String orderNo, Long apiClientId) {
		if (StrUtils.isNULL(orderNo)) {
			throw new ServiceException(StatusHouse.COMMON_STATUS_PARAM_REQUIRED_ERROR, "订单号");
		}
		Order order = orderRepository.findOrderByOrderNo(orderNo, apiClientId);
		if (order == null) {
			throw new ServiceException(StatusHouse.ORDER_NOT_EXIST);
		}
		if (order.getStatus() != 2) {
			throw new ServiceException(StatusHouse.ORDER_IS_NOT_DISTRIBUTE);
		}
		order.setStatus(3);
		orderRepository.update(order);

		return order;
	}

	@Override
	public List<Order> findOrders(Long memberId, Integer status, Long apiClientId) {
		return orderRepository.findOrders(memberId, status, apiClientId);
	}

}
